package ru.electron.menu.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;

import static android.provider.BaseColumns._ID;

public class MenuProvider extends ContentProvider {


    public static final String AUTHORITY = "ru.electron.menu";
    private static final String CONTENT_URI_STRING = "content://" + AUTHORITY + "/";
    public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);

    private static final String DATABASE_NAME = "menu.db";
    private static final int DATABASE_VERSION = 2;

    private static final String TABLE_TAGS = "tags";
    public static final String KEY_TAG_NAME = "tag_name";
    public static final int CODE_TAGS = 0;
    private static final int CODE_TAG = 5;

    private static final String TABLE_DISHES = "dishes";
    public static final String KEY_URI = "uri";
    public static final String KEY_PRICE = "price";
    public static final String KEY_DESCRIPTION = "description";
    public static final String KEY_DISH_NAME = "dish_name";
    public static final String KEY_AVAILABILITY = "available";
    public static final String KEY_TAG_ID = "tag_id";
    public static final String KEY_COUNT = "count";
    public static final String KEY_ORDERED = "ordered";


//    private static final String Table


    public static final int CODE_AVAILABLE_DISHES = 1;
    public static final int CODE_DISH = 2;
    public static final int CODE_DISHES = 3;
    private static final int CODE_AVAILABLE_DISHES_WITH_TAG = 4;

    private static final int CODE_ORDER = 6;
    private static final int CODE_ORDERS = 7;

    private static final int CODE_SENT = 8;

    private static final String ORDER_PART = "/ordered";
    private static final String AVAILABLE_PART = "/available";
    private static final String SENT_PART = "/sent";

    public static final Uri URI_TAGS = Uri.withAppendedPath(CONTENT_URI, TABLE_TAGS);
    public static final Uri URI_ORDER = Uri.withAppendedPath(CONTENT_URI, TABLE_DISHES + ORDER_PART);
    public static final Uri URI_DISHES = Uri.withAppendedPath(CONTENT_URI, TABLE_DISHES);
    public static final Uri URI_AVAILABLE_DISHES = Uri.withAppendedPath(CONTENT_URI, TABLE_DISHES + AVAILABLE_PART);
    public static final Uri URI_SENT = Uri.withAppendedPath(CONTENT_URI, TABLE_DISHES + SENT_PART);

    private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);


    static {
        uriMatcher.addURI(AUTHORITY, TABLE_TAGS, CODE_TAGS);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + AVAILABLE_PART, CODE_AVAILABLE_DISHES);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + "/#", CODE_DISH);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES, CODE_DISHES);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + AVAILABLE_PART + "/#", CODE_AVAILABLE_DISHES_WITH_TAG);
        uriMatcher.addURI(AUTHORITY, TABLE_TAGS + "/#", CODE_TAG);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + ORDER_PART + "/#", CODE_ORDER);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + ORDER_PART, CODE_ORDERS);
        uriMatcher.addURI(AUTHORITY, TABLE_DISHES + SENT_PART, CODE_SENT);
    }


    private void dumpBase(String table) {
        Cursor c = menuDB.query(table, null, null, null, null, null, null, null);
        Log.e("columns", table + " " + Arrays.toString(c.getColumnNames()));
        c.close();
    }


    private static String DATABASE_CREATE_TAGS = "create table "
            + TABLE_TAGS + " (" + _ID
            + " integer primary key, " + KEY_TAG_NAME
            + " TEXT not null);";

    private static String DATABASE_CREATE_DISHES = "create table "
            + TABLE_DISHES + " ("
            + _ID + " integer primary key, "
            + KEY_DISH_NAME + " TEXT not null, "
            + KEY_PRICE + " FLOAT, "
            + KEY_URI + " Text, "
            + KEY_AVAILABILITY + " INTEGER, "
            + KEY_TAG_ID + " INTEGER, "
            + KEY_ORDERED + " INTEGER default 0, "
            + KEY_COUNT + " INTEGER default 0, "

            + KEY_DESCRIPTION + " Text not null, " +
            "FOREIGN KEY(" + KEY_TAG_ID + ") REFERENCES " + TABLE_TAGS + "(" + _ID + ")" +
            ");";

    private boolean wasCreated = false;

    private class DataBaseHelper extends SQLiteOpenHelper {


        private Context context;

        public DataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
            this.context = context;
        }


        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {
            sqLiteDatabase.execSQL(DATABASE_CREATE_TAGS);
            sqLiteDatabase.execSQL(DATABASE_CREATE_DISHES);
            wasCreated = true;

        }

        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

        }

    }


    private SQLiteDatabase menuDB;


    @Override
    public boolean onCreate() {
        try {
            DataBaseHelper dataBaseHelper = new DataBaseHelper(getContext(), DATABASE_NAME, null, DATABASE_VERSION);

            menuDB = dataBaseHelper.getWritableDatabase();
//            if (wasCreated) {
//                try {
//                    InputStream stream = getContext().getAssets().open("dishes.txt");
//                    BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
//                    MenuInitializator initializator = new MenuInitializator();
//                    initializator.init(getContext(), reader.readLine());
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        switch (uriMatcher.match(uri)) {
            case CODE_AVAILABLE_DISHES:
                builder.setTables(TABLE_DISHES);
                builder.appendWhere(KEY_AVAILABILITY + "=1");
                break;
            case CODE_AVAILABLE_DISHES_WITH_TAG:
                builder.setTables(TABLE_DISHES);
                builder.appendWhere(KEY_AVAILABILITY + "=1 AND " + KEY_TAG_ID + "=" + uri.getLastPathSegment());

                break;
            case CODE_DISH:
                builder.setTables(TABLE_DISHES);
                builder.appendWhere(_ID + "=" + uri.getLastPathSegment());
                break;
            case CODE_TAGS:
                builder.setTables(TABLE_TAGS);
                break;
            case CODE_TAG:
                builder.setTables(TABLE_TAGS);
                builder.appendWhere(_ID + "=" + uri.getLastPathSegment());
                break;
            case CODE_ORDERS:
                builder.setTables(TABLE_DISHES);
                builder.appendWhere(KEY_COUNT + ">0");
                break;
            case CODE_SENT:
                builder.setTables(TABLE_DISHES);
                builder.appendWhere(KEY_ORDERED + ">0");
                break;
        }
        Cursor c = builder.query(menuDB, projection, selection, selectionArgs, null, null, sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), CONTENT_URI);
        return c;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }


    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        switch (uriMatcher.match(uri)) {
            case CODE_DISHES:
                menuDB.insert(TABLE_DISHES, null, contentValues);
                break;
            case CODE_TAGS:
                menuDB.insert(TABLE_TAGS, null, contentValues);
                break;
        }
        getContext().getContentResolver().notifyChange(CONTENT_URI, null);
        //TODO: we don't need it now. but it is bad practice to return null here
        return null;
    }

    @Override
    public int delete(Uri uri, String s, String[] strings) {
        switch (uriMatcher.match(uri)) {
            case CODE_SENT:
//                ContentValues values = new ContentValues();
//                values.put(KEY_COUNT, 0);
//                int res = menuDB.update(TABLE_DISHES, values, null, null);
                menuDB.execSQL("UPDATE " + TABLE_DISHES + " SET " + KEY_ORDERED + "=" + "(" + KEY_COUNT + "+ " + KEY_ORDERED + ")");

                menuDB.execSQL("UPDATE " + TABLE_DISHES + " SET " + KEY_COUNT + "= 0");

                getContext().getContentResolver().notifyChange(CONTENT_URI, null);
                return 0/*res*/;
            case CODE_ORDERS:
                menuDB.execSQL("UPDATE " + TABLE_DISHES + " SET " + KEY_COUNT + "= 0");
                return 0;
            default:
                menuDB.delete(TABLE_DISHES, null, null);
                menuDB.delete(TABLE_TAGS, null, null);
                getContext().getContentResolver().notifyChange(CONTENT_URI, null);
        }
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
        switch (uriMatcher.match(uri)) {
            case CODE_ORDER:
                String where = _ID + "=" + uri.getLastPathSegment();
                getContext().getContentResolver().notifyChange(CONTENT_URI, null);

                return menuDB.update(TABLE_DISHES, contentValues, where, null);
        }
        return 0;
    }
}
